#ifndef _MSSQLACCESS_H_
#define _MSSQLACCESS_H_
#include <Client/ClientUtils/Network/AbstractRDBAccess.h>
#include <Client/ClientUtils/Network/mssql/MSSQLDriver.h>

namespace GST {
namespace ClientUtils	{

class GST_API_EXPORT MSSQLAccess :
	public AbstractRDBAccess
{
public:
	/**
	 * @note
	 * If odbcclientversion is empty we try to get it from the registry
	 *
	 * @throw GST::exceptions::GSTNotFound if odbcclientversion is empty and no entry found in registry
	 */
	MSSQLAccess(HostPtr host, const std::string& DB, RDBConfigPtr dbconfig, const std::string& odbcclientversion = std::string());
	MSSQLAccess(const MSSQLDriver& driver, RDBConfigPtr dbconfig );
	~MSSQLAccess(void);
	virtual NetworkPtr fork() const;
	virtual NetworkPtr reconnect(const std::string & user, const std::string & pwd, const std::string & db="") const;
	virtual bool isSuperUserConnection() const;
	virtual UserPtr getCurrentGSTUser() const;
	virtual BackendType GetBackendType() const;
	virtual void CreatePropertyTable( const FeatureClassDesc& featureClass, const GeoColumnDesc & geocolumn );
	virtual void CreateFeatureClass_Impl( const FeatureClassDetailedDesc& featureClassDesc );
	virtual void CreateTable( const GST::ClientUtils::TableAttributeDescList & attributes, bool quoteTablename );
	virtual CrudeFeaturePtr GetFeature( const FeatureDesc & feature , const IGeometry::RequestFormat & geometryformat, Geometry::SRSPtr srs, bool lock = false, QueryBoxPtr queryBox = QueryBoxPtr(), long commitKey = -1 );
	virtual AssignableFeatureDescListPtr ListAllFeatures(const FeatureClassDesc& featureClass) const;
	virtual void SimplifyFeature( const FeatureDesc & feature );
	virtual FeatureDescPtr UploadNewFeature( const Geometry::StreamableGeometry & feature, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
	virtual void UpdateFeature( const Geometry::StreamableGeometry & feature, const std::string & lockid, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
	virtual void UpdateFeatureKeepLock( const Geometry::StreamableGeometry & feature, const std::string & lockid, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
	virtual void UnlockByKey( const std::string & key );
	virtual void ExecuteScript( const std::string & script );
	virtual CrudeFeaturePtr GetFeatureBinary( const FeatureDesc & feature, Geometry::SRSPtr srs, QueryBoxPtr queryBox = QueryBoxPtr(), long commitKey = -1);
	virtual void RenameProperty_Impl( const FeatureClassDesc& featureClass, TableAttributeDescPtr attribute, const std::string& newName ) const;
	virtual ServiceDescriptionPtr CreateService(const std::string &name, const std::string &url, long accessLevelId, const std::string &user, const std::string &secret) const;
	virtual ServiceDescriptionPtr UpdateService(long serviceId, const std::string &name, const std::string &url, long accessLevelId, const std::string &user, const std::string &secret) const;

	virtual ColorMap::Id InsertColorMap(  const std::string & name, const Geometry::IGeometry::Color & nodataColor, const std::string &regex, long accessLevelId );
	virtual ServerInfoPtr GetServerInformation();
	virtual FeatureDescPtr GetFeatureDescByGeomId( const long & idgeo ) const;
	///@name user handling
	//@{
	virtual void CreateUser(const User& user, const std::string & initialgroupName);
	virtual UserListPtr GetUsersByGroup( const std::string& groupName ) const;
	virtual GroupListPtr GetGroupsByUser( const std::string& userName) const;
	virtual GroupListPtr GetGroupsByCurrentUser() const;
	virtual void ChangeUserPassword(const std::string& userName, const std::string &newPassword, const std::string &oldPassword) const;
	//@}
	virtual NamesListPtr ListAllTables() const;
	virtual std::string GetExactColumnDataType(const std::string& columnname) const;
	virtual NamesListPtr ListAllColumns(const std::string& tablename) const;
	virtual bool ViewRefersTable(const std::string& tablename, const std::string& viewname) const;
	virtual NamesListPtr ListAllViewsRefersTable(const std::string& tablename) const;

	virtual NamesListPtr ListPrimaryKeyColumns(const std::string& tablename) const;
	virtual ClientUtils::TableAttributeDesc::DType GetColumnDType(const std::string& columnname) const;


	///@name Version handling
	//@{
	virtual Utils::GSTVersionPtr GetStorageVersion() const;
	virtual int CheckCompatibility(const std::string &client_version) const;
	//@}
	//@}

	///@name Version MoMa
	//@{
	virtual LinkAdjacencyPtr CreateLinkAdjacency(LinkAdjacency::LinkId parent, LinkAdjacency::ReferId refId, LinkAdjacency::TargetType refTarget, Owner::OwnerId owner) const;
	virtual ColorScale::ColorScaleId AddColorScale(ColorScalePtr cs) const;
	virtual ColorValue::ColorValueId AddColorValue(ColorValuePtr cv) const;
	virtual FeatureLinkIdGeometryIdPairListPtr ResolveGeometries( LinkAdjacency::LinkId rootElement, LinkAdjacency::LinkId csRootElement = ROOT_NODE_LINKID, ColorScale::ColorScaleId csRootScale = -1 ) const;
	virtual CrudeFeaturePtr GetFeatureFromMoMa(	LinkAdjacency::LinkId flid
												, const IGeometry::RequestFormat & geometryformat
												, Geometry::SRSPtr srs
												, LinkAdjacency::LinkId csRootElement = ROOT_NODE_LINKID
												, ColorScale::ColorScaleId csRootScale = -1
												, bool lock = false
												, QueryBoxPtr queryBox = QueryBoxPtr() 
												, long commitKey = -1) const;
	virtual void CreateElement(ElementPtr element, bool uniqueName = false) const;
	virtual QueryBoxPtr GetBboxFromMoma(const MoMaKey &momakey,
		Geometry::SRSPtr targetSrs) const;
	virtual MoMaPropertyDescPtr CreateMoMaPropertyDesc(const std::string& name, TableAttributeDesc::DType dtype, Owner::OwnerId owner) const;
	virtual MoMaPropertyValueListPtr GetMoMaPropertyValuesForNode(const LinkedElement& element) const;

	//@}

	///@name Model Management
	//@{
	virtual OwnerListPtr GetOwners() const;
	//@}


	///@name Versioning
	//@{

	virtual long BeginCommit(const std::string &message) const;
	virtual int EndCommit(long commitKey) const;
	//@}

	///@name AbstractRDBAccess interface
	//@{
	virtual RDBDriverInterface * getRDBDriver() const{return this->dbconnection.get();}
	virtual void RunPreparedInsertStatement(const InsertStatementDesc & preparedStatement);
	virtual void RunPreparedUpdateStatement(const UpdateStatementDesc & preparedStatement);
	//@}

	virtual void updateSchemaStats() const;

	protected:

	///@name virtual helpers
	//@{
	virtual std::string formatDateTimeStamp( const std::string & colName ) const;
	virtual AbstractRDBAttributeVal * newAttributeVal(const TableAttributeVal & val) const;
	virtual AbstractRDBAttributeDesc * newAttributeDesc(const TableAttributeDesc & desc, bool is_primaryKey=false) const;
	virtual void RunSP(SPDescPtr storedProcedure) const;
	virtual std::string GlueAttributeNames(const TableAttributeValList & attributes, const std::string & glue=std::string(",")) const;
	virtual void RenameFeatureClass_Impl( const FeatureClassDesc& featureClassDesc, const std::string& newName );

	virtual TableAttributeDescListPtr GetPrimaryKey(const std::string & tablename) const;
	void UpdateFeature_impl( const Geometry::StreamableGeometry & feature, const std::string & lockid, bool keepLock, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
	//@}

	private:
	///@name SQL generation helper
	//@{
	virtual void GenSQLForeignKeyConstraint(ForeignKeyPtr kc, const std::string& cpname, std::string& sql_OUT);
	virtual std::string GenSQLDeleteColumn(ForeignKeyPtr fk);
	virtual std::string GenSQLEndTransaction(const std::string& errormessage="");
	virtual std::string GenSQLBeginTransaction();
	virtual std::string GenSQLAddColumn( const std::string & table, const TableAttributeDesc& attribute );
	virtual std::string GenSQLValueList( const TableAttributeValList & attributes, const std::string & glue=std::string(",") );
	std::string GenSQLDeleteFKConstraint(ForeignKeyPtr kc);
	std::string GenSQLReplaceMultipleIdentityColumns(const std::string& sql);
	//@}

	MSSQLDriver * getDriver() const {return dynamic_cast<MSSQLDriver *>(this->dbconnection.get());};
	void GetErrorMessage(unsigned int handletype, void* handle, std::string query) const;
	virtual void constructVariousPropertyNameAndValueList( bool updateSyntax, Geometry::StreamableGeometry::KeyValueListPtr variousProperties, TableAttributeDescListPtr attributes, std::string &variousPropertiesNames, std::string &variousPropertiesValues, const std::string & ignore, const std::string & warn_methodname, const bool executeimmediatesyntax = false ) const;
	virtual GST::Protocol GetProtocol() const;
	void handleExceptions(const std::string &functionName, const std::string &sprocName = std::string()) const;
	virtual void CheckIfElementNameIsUnique_impl(const std::string &name, std::string& sqlstatement) const;
	bool CheckExistenceFKConstraint(ForeignKeyPtr kc, const bool isUpdateCascade = true);
	TableAttributeKeyDescListPtr GetPrimaryKey_impl(const std::string & tablename) const;

};

struct GST_API_EXPORT MSSQLRecordFeature
	: public CrudeFeature
{
	AbstractDataTablePtr data;
	TableAttributeValListPtr objProperties;

	virtual std::string GetGeometry();
	virtual std::string GetPropertyVals();
	virtual std::string GetLockId();
	virtual TableAttributeValListPtr GetObjProperties() { return objProperties; }
};


}//of ns ClientUtils
} //of ns GST

#endif 
